{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Looking in indexes: http://mirrors.aliyun.com/pypi/simple/\n",
      "Requirement already satisfied: langchain in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (0.3.19)\n",
      "Requirement already satisfied: langchain-core<1.0.0,>=0.3.35 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain) (0.3.39)\n",
      "Requirement already satisfied: langchain-text-splitters<1.0.0,>=0.3.6 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain) (0.3.6)\n",
      "Requirement already satisfied: langsmith<0.4,>=0.1.17 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain) (0.3.11)\n",
      "Requirement already satisfied: pydantic<3.0.0,>=2.7.4 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain) (2.10.6)\n",
      "Requirement already satisfied: SQLAlchemy<3,>=1.4 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain) (2.0.38)\n",
      "Requirement already satisfied: requests<3,>=2 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain) (2.32.3)\n",
      "Requirement already satisfied: PyYAML>=5.3 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain) (6.0.2)\n",
      "Requirement already satisfied: aiohttp<4.0.0,>=3.8.3 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain) (3.11.13)\n",
      "Requirement already satisfied: tenacity!=8.4.0,<10,>=8.1.0 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain) (9.0.0)\n",
      "Requirement already satisfied: numpy<2,>=1.26.4 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain) (1.26.4)\n",
      "Requirement already satisfied: aiohappyeyeballs>=2.3.0 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (2.4.6)\n",
      "Requirement already satisfied: aiosignal>=1.1.2 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (1.3.2)\n",
      "Requirement already satisfied: attrs>=17.3.0 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (25.1.0)\n",
      "Requirement already satisfied: frozenlist>=1.1.1 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (1.5.0)\n",
      "Requirement already satisfied: multidict<7.0,>=4.5 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (6.1.0)\n",
      "Requirement already satisfied: propcache>=0.2.0 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (0.3.0)\n",
      "Requirement already satisfied: yarl<2.0,>=1.17.0 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (1.18.3)\n",
      "Requirement already satisfied: jsonpatch<2.0,>=1.33 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain-core<1.0.0,>=0.3.35->langchain) (1.33)\n",
      "Requirement already satisfied: packaging<25,>=23.2 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain-core<1.0.0,>=0.3.35->langchain) (24.2)\n",
      "Requirement already satisfied: typing-extensions>=4.7 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain-core<1.0.0,>=0.3.35->langchain) (4.12.2)\n",
      "Requirement already satisfied: httpx<1,>=0.23.0 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langsmith<0.4,>=0.1.17->langchain) (0.28.1)\n",
      "Requirement already satisfied: orjson<4.0.0,>=3.9.14 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langsmith<0.4,>=0.1.17->langchain) (3.10.15)\n",
      "Requirement already satisfied: requests-toolbelt<2.0.0,>=1.0.0 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langsmith<0.4,>=0.1.17->langchain) (1.0.0)\n",
      "Requirement already satisfied: zstandard<0.24.0,>=0.23.0 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langsmith<0.4,>=0.1.17->langchain) (0.23.0)\n",
      "Requirement already satisfied: annotated-types>=0.6.0 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from pydantic<3.0.0,>=2.7.4->langchain) (0.7.0)\n",
      "Requirement already satisfied: pydantic-core==2.27.2 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from pydantic<3.0.0,>=2.7.4->langchain) (2.27.2)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from requests<3,>=2->langchain) (3.4.1)\n",
      "Requirement already satisfied: idna<4,>=2.5 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from requests<3,>=2->langchain) (3.10)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from requests<3,>=2->langchain) (2.3.0)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from requests<3,>=2->langchain) (2025.1.31)\n",
      "Requirement already satisfied: greenlet!=0.4.17 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from SQLAlchemy<3,>=1.4->langchain) (3.1.1)\n",
      "Requirement already satisfied: anyio in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from httpx<1,>=0.23.0->langsmith<0.4,>=0.1.17->langchain) (4.8.0)\n",
      "Requirement already satisfied: httpcore==1.* in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from httpx<1,>=0.23.0->langsmith<0.4,>=0.1.17->langchain) (1.0.7)\n",
      "Requirement already satisfied: h11<0.15,>=0.13 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from httpcore==1.*->httpx<1,>=0.23.0->langsmith<0.4,>=0.1.17->langchain) (0.14.0)\n",
      "Requirement already satisfied: jsonpointer>=1.9 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from jsonpatch<2.0,>=1.33->langchain-core<1.0.0,>=0.3.35->langchain) (3.0.0)\n",
      "Requirement already satisfied: sniffio>=1.1 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from anyio->httpx<1,>=0.23.0->langsmith<0.4,>=0.1.17->langchain) (1.3.1)\n",
      "Looking in indexes: http://mirrors.aliyun.com/pypi/simple/\n",
      "Requirement already satisfied: langchain-core in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (0.3.39)\n",
      "Requirement already satisfied: langgraph in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (0.2.74)\n",
      "Requirement already satisfied: langsmith<0.4,>=0.1.125 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain-core) (0.3.11)\n",
      "Requirement already satisfied: tenacity!=8.4.0,<10.0.0,>=8.1.0 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain-core) (9.0.0)\n",
      "Requirement already satisfied: jsonpatch<2.0,>=1.33 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain-core) (1.33)\n",
      "Requirement already satisfied: PyYAML>=5.3 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain-core) (6.0.2)\n",
      "Requirement already satisfied: packaging<25,>=23.2 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain-core) (24.2)\n",
      "Requirement already satisfied: typing-extensions>=4.7 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain-core) (4.12.2)\n",
      "Requirement already satisfied: pydantic<3.0.0,>=2.5.2 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain-core) (2.10.6)\n",
      "Requirement already satisfied: langgraph-checkpoint<3.0.0,>=2.0.10 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langgraph) (2.0.16)\n",
      "Requirement already satisfied: langgraph-sdk<0.2.0,>=0.1.42 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langgraph) (0.1.53)\n",
      "Requirement already satisfied: jsonpointer>=1.9 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from jsonpatch<2.0,>=1.33->langchain-core) (3.0.0)\n",
      "Requirement already satisfied: msgpack<2.0.0,>=1.1.0 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langgraph-checkpoint<3.0.0,>=2.0.10->langgraph) (1.1.0)\n",
      "Requirement already satisfied: httpx>=0.25.2 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langgraph-sdk<0.2.0,>=0.1.42->langgraph) (0.28.1)\n",
      "Requirement already satisfied: orjson>=3.10.1 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langgraph-sdk<0.2.0,>=0.1.42->langgraph) (3.10.15)\n",
      "Requirement already satisfied: requests<3,>=2 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langsmith<0.4,>=0.1.125->langchain-core) (2.32.3)\n",
      "Requirement already satisfied: requests-toolbelt<2.0.0,>=1.0.0 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langsmith<0.4,>=0.1.125->langchain-core) (1.0.0)\n",
      "Requirement already satisfied: zstandard<0.24.0,>=0.23.0 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langsmith<0.4,>=0.1.125->langchain-core) (0.23.0)\n",
      "Requirement already satisfied: annotated-types>=0.6.0 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from pydantic<3.0.0,>=2.5.2->langchain-core) (0.7.0)\n",
      "Requirement already satisfied: pydantic-core==2.27.2 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from pydantic<3.0.0,>=2.5.2->langchain-core) (2.27.2)\n",
      "Requirement already satisfied: anyio in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from httpx>=0.25.2->langgraph-sdk<0.2.0,>=0.1.42->langgraph) (4.8.0)\n",
      "Requirement already satisfied: certifi in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from httpx>=0.25.2->langgraph-sdk<0.2.0,>=0.1.42->langgraph) (2025.1.31)\n",
      "Requirement already satisfied: httpcore==1.* in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from httpx>=0.25.2->langgraph-sdk<0.2.0,>=0.1.42->langgraph) (1.0.7)\n",
      "Requirement already satisfied: idna in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from httpx>=0.25.2->langgraph-sdk<0.2.0,>=0.1.42->langgraph) (3.10)\n",
      "Requirement already satisfied: h11<0.15,>=0.13 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from httpcore==1.*->httpx>=0.25.2->langgraph-sdk<0.2.0,>=0.1.42->langgraph) (0.14.0)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from requests<3,>=2->langsmith<0.4,>=0.1.125->langchain-core) (3.4.1)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from requests<3,>=2->langsmith<0.4,>=0.1.125->langchain-core) (2.3.0)\n",
      "Requirement already satisfied: sniffio>=1.1 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from anyio->httpx>=0.25.2->langgraph-sdk<0.2.0,>=0.1.42->langgraph) (1.3.1)\n",
      "Looking in indexes: http://mirrors.aliyun.com/pypi/simple/\n",
      "Collecting langchain-ollama\n",
      "  Downloading http://mirrors.aliyun.com/pypi/packages/85/72/f7301340a544fea1c139c64590044f0beb5bfba889b8f6e50766b933e660/langchain_ollama-0.2.3-py3-none-any.whl (19 kB)\n",
      "Requirement already satisfied: langchain-core<0.4.0,>=0.3.33 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain-ollama) (0.3.39)\n",
      "Collecting ollama<1,>=0.4.4 (from langchain-ollama)\n",
      "  Downloading http://mirrors.aliyun.com/pypi/packages/31/83/c3ffac86906c10184c88c2e916460806b072a2cfe34cdcaf3a0c0e836d39/ollama-0.4.7-py3-none-any.whl (13 kB)\n",
      "Requirement already satisfied: langsmith<0.4,>=0.1.125 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain-core<0.4.0,>=0.3.33->langchain-ollama) (0.3.11)\n",
      "Requirement already satisfied: tenacity!=8.4.0,<10.0.0,>=8.1.0 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain-core<0.4.0,>=0.3.33->langchain-ollama) (9.0.0)\n",
      "Requirement already satisfied: jsonpatch<2.0,>=1.33 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain-core<0.4.0,>=0.3.33->langchain-ollama) (1.33)\n",
      "Requirement already satisfied: PyYAML>=5.3 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain-core<0.4.0,>=0.3.33->langchain-ollama) (6.0.2)\n",
      "Requirement already satisfied: packaging<25,>=23.2 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain-core<0.4.0,>=0.3.33->langchain-ollama) (24.2)\n",
      "Requirement already satisfied: typing-extensions>=4.7 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain-core<0.4.0,>=0.3.33->langchain-ollama) (4.12.2)\n",
      "Requirement already satisfied: pydantic<3.0.0,>=2.5.2 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langchain-core<0.4.0,>=0.3.33->langchain-ollama) (2.10.6)\n",
      "Requirement already satisfied: httpx<0.29,>=0.27 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from ollama<1,>=0.4.4->langchain-ollama) (0.28.1)\n",
      "Requirement already satisfied: anyio in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from httpx<0.29,>=0.27->ollama<1,>=0.4.4->langchain-ollama) (4.8.0)\n",
      "Requirement already satisfied: certifi in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from httpx<0.29,>=0.27->ollama<1,>=0.4.4->langchain-ollama) (2025.1.31)\n",
      "Requirement already satisfied: httpcore==1.* in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from httpx<0.29,>=0.27->ollama<1,>=0.4.4->langchain-ollama) (1.0.7)\n",
      "Requirement already satisfied: idna in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from httpx<0.29,>=0.27->ollama<1,>=0.4.4->langchain-ollama) (3.10)\n",
      "Requirement already satisfied: h11<0.15,>=0.13 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from httpcore==1.*->httpx<0.29,>=0.27->ollama<1,>=0.4.4->langchain-ollama) (0.14.0)\n",
      "Requirement already satisfied: jsonpointer>=1.9 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from jsonpatch<2.0,>=1.33->langchain-core<0.4.0,>=0.3.33->langchain-ollama) (3.0.0)\n",
      "Requirement already satisfied: orjson<4.0.0,>=3.9.14 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langsmith<0.4,>=0.1.125->langchain-core<0.4.0,>=0.3.33->langchain-ollama) (3.10.15)\n",
      "Requirement already satisfied: requests<3,>=2 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langsmith<0.4,>=0.1.125->langchain-core<0.4.0,>=0.3.33->langchain-ollama) (2.32.3)\n",
      "Requirement already satisfied: requests-toolbelt<2.0.0,>=1.0.0 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langsmith<0.4,>=0.1.125->langchain-core<0.4.0,>=0.3.33->langchain-ollama) (1.0.0)\n",
      "Requirement already satisfied: zstandard<0.24.0,>=0.23.0 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from langsmith<0.4,>=0.1.125->langchain-core<0.4.0,>=0.3.33->langchain-ollama) (0.23.0)\n",
      "Requirement already satisfied: annotated-types>=0.6.0 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from pydantic<3.0.0,>=2.5.2->langchain-core<0.4.0,>=0.3.33->langchain-ollama) (0.7.0)\n",
      "Requirement already satisfied: pydantic-core==2.27.2 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from pydantic<3.0.0,>=2.5.2->langchain-core<0.4.0,>=0.3.33->langchain-ollama) (2.27.2)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from requests<3,>=2->langsmith<0.4,>=0.1.125->langchain-core<0.4.0,>=0.3.33->langchain-ollama) (3.4.1)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from requests<3,>=2->langsmith<0.4,>=0.1.125->langchain-core<0.4.0,>=0.3.33->langchain-ollama) (2.3.0)\n",
      "Requirement already satisfied: sniffio>=1.1 in c:\\users\\rf.yin\\.conda\\envs\\pydantic-ai\\lib\\site-packages (from anyio->httpx<0.29,>=0.27->ollama<1,>=0.4.4->langchain-ollama) (1.3.1)\n",
      "Installing collected packages: ollama, langchain-ollama\n",
      "Successfully installed langchain-ollama-0.2.3 ollama-0.4.7\n"
     ]
    }
   ],
   "source": [
    "! pip install langchain\n",
    "! pip install langchain-core langgraph\n",
    "\n",
    "! pip install langchain-ollama"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'{\"location\": \"Los Angeles\", \"time_of_day\": \"15:00\"}'"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_ollama import ChatOllama\n",
    "from langchain_core.messages import HumanMessage, AIMessage\n",
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "\n",
    "prompt = ChatPromptTemplate.from_messages([\n",
    "    (\n",
    "        \"system\",\n",
    "        \"Return a query for the weather in {city} and time of day with two keys: location and time_of_day. Respond using JSON only.\",\n",
    "    )\n",
    "])\n",
    "\n",
    "\n",
    "llm = ChatOllama(\n",
    "    model = \"qwen2.5:7b\",\n",
    "    temperature = 0.2,\n",
    "    base_url = \"http://192.168.31.240:11434\",\n",
    "    format=\"json\"\n",
    "\n",
    ")\n",
    "json_schema = {\n",
    "    \"type\": \"object\",\n",
    "    \"properties\": {\n",
    "        \"location\": {\"type\": \"string\"},\n",
    "        \"time_of_day\": {\"type\": \"string\"},\n",
    "        \"weather\": {\"type\": \"string\"}\n",
    "    }\n",
    "}\n",
    "\n",
    "messages = [\n",
    "    (\"human\", \"Return a query for the weather in a random location and time of day with two keys: location and time_of_day. Respond using JSON only.\"),\n",
    "]\n",
    "llm.invoke(messages).content\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "ename": "ValidationError",
     "evalue": "10 validation errors for NovelDataListModel\nnovel_list.0.type\n  Field required [type=missing, input_value={'emotion': '', 'speaker'...墙点了一支烟。'}, input_type=dict]\n    For further information visit https://errors.pydantic.dev/2.10/v/missing\nnovel_list.0.character\n  Field required [type=missing, input_value={'emotion': '', 'speaker'...墙点了一支烟。'}, input_type=dict]\n    For further information visit https://errors.pydantic.dev/2.10/v/missing\nnovel_list.1.type\n  Field required [type=missing, input_value={'emotion': '', 'speaker'...青春，真可爱！'}, input_type=dict]\n    For further information visit https://errors.pydantic.dev/2.10/v/missing\nnovel_list.1.character\n  Field required [type=missing, input_value={'emotion': '', 'speaker'...青春，真可爱！'}, input_type=dict]\n    For further information visit https://errors.pydantic.dev/2.10/v/missing\nnovel_list.2.type\n  Field required [type=missing, input_value={'emotion': '', 'speaker'...小萝莉走过去。'}, input_type=dict]\n    For further information visit https://errors.pydantic.dev/2.10/v/missing\nnovel_list.2.character\n  Field required [type=missing, input_value={'emotion': '', 'speaker'...小萝莉走过去。'}, input_type=dict]\n    For further information visit https://errors.pydantic.dev/2.10/v/missing\nnovel_list.3.type\n  Field required [type=missing, input_value={'emotion': '', 'speaker'...伸向了小萝莉。'}, input_type=dict]\n    For further information visit https://errors.pydantic.dev/2.10/v/missing\nnovel_list.3.character\n  Field required [type=missing, input_value={'emotion': '', 'speaker'...伸向了小萝莉。'}, input_type=dict]\n    For further information visit https://errors.pydantic.dev/2.10/v/missing\nnovel_list.4.type\n  Field required [type=missing, input_value={'emotion': '', 'speaker'...里骂道：禽兽。'}, input_type=dict]\n    For further information visit https://errors.pydantic.dev/2.10/v/missing\nnovel_list.4.character\n  Field required [type=missing, input_value={'emotion': '', 'speaker'...里骂道：禽兽。'}, input_type=dict]\n    For further information visit https://errors.pydantic.dev/2.10/v/missing",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mValidationError\u001b[0m                           Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[2], line 71\u001b[0m\n\u001b[0;32m     60\u001b[0m chain \u001b[38;5;241m=\u001b[39m prompt_template \u001b[38;5;241m|\u001b[39m structured_llm\n\u001b[0;32m     62\u001b[0m novel_text \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\"\"\u001b[39m\n\u001b[0;32m     63\u001b[0m \u001b[38;5;124m故事开始的那天，我照例是上着班，打扫完一片狼藉的宠物店，走出店门口，在隔壁便利店买了一包五块钱的软白沙，疲惫的靠着墙点了一支烟。\u001b[39m\n\u001b[0;32m     64\u001b[0m \u001b[38;5;124m店门口的台阶上，一字排开坐了一行人，有老有少，有男有女。有个白嫩的小萝莉，全身汗津津的，bra在校服下若隐若现。青春，真可爱青春。\u001b[39m\n\u001b[1;32m   (...)\u001b[0m\n\u001b[0;32m     67\u001b[0m \u001b[38;5;124m我在心里骂，禽兽。\u001b[39m\n\u001b[0;32m     68\u001b[0m \u001b[38;5;124m\"\"\"\u001b[39m\n\u001b[1;32m---> 71\u001b[0m response \u001b[38;5;241m=\u001b[39m \u001b[43mchain\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\u001b[43m{\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mnovel_text\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mnovel_text\u001b[49m\u001b[43m}\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m     72\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;28mtype\u001b[39m(response))\n\u001b[0;32m     73\u001b[0m \u001b[38;5;28mprint\u001b[39m(response\u001b[38;5;241m.\u001b[39mmodel_dump_json(indent\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m4\u001b[39m))\n",
      "File \u001b[1;32mc:\\Users\\rf.yin\\.conda\\envs\\langchain_0_3\\Lib\\site-packages\\langchain_core\\runnables\\base.py:3024\u001b[0m, in \u001b[0;36mRunnableSequence.invoke\u001b[1;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[0;32m   3022\u001b[0m             \u001b[38;5;28minput\u001b[39m \u001b[38;5;241m=\u001b[39m context\u001b[38;5;241m.\u001b[39mrun(step\u001b[38;5;241m.\u001b[39minvoke, \u001b[38;5;28minput\u001b[39m, config, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[0;32m   3023\u001b[0m         \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m-> 3024\u001b[0m             \u001b[38;5;28minput\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[43mcontext\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\u001b[43mstep\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m   3025\u001b[0m \u001b[38;5;66;03m# finish the root run\u001b[39;00m\n\u001b[0;32m   3026\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n",
      "File \u001b[1;32mc:\\Users\\rf.yin\\.conda\\envs\\langchain_0_3\\Lib\\site-packages\\langchain_core\\output_parsers\\base.py:193\u001b[0m, in \u001b[0;36mBaseOutputParser.invoke\u001b[1;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[0;32m    186\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21minvoke\u001b[39m(\n\u001b[0;32m    187\u001b[0m     \u001b[38;5;28mself\u001b[39m,\n\u001b[0;32m    188\u001b[0m     \u001b[38;5;28minput\u001b[39m: Union[\u001b[38;5;28mstr\u001b[39m, BaseMessage],\n\u001b[0;32m    189\u001b[0m     config: Optional[RunnableConfig] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[0;32m    190\u001b[0m     \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any,\n\u001b[0;32m    191\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m T:\n\u001b[0;32m    192\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(\u001b[38;5;28minput\u001b[39m, BaseMessage):\n\u001b[1;32m--> 193\u001b[0m         \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_call_with_config\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m    194\u001b[0m \u001b[43m            \u001b[49m\u001b[38;5;28;43;01mlambda\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43minner_input\u001b[49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mparse_result\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m    195\u001b[0m \u001b[43m                \u001b[49m\u001b[43m[\u001b[49m\u001b[43mChatGeneration\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmessage\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43minner_input\u001b[49m\u001b[43m)\u001b[49m\u001b[43m]\u001b[49m\n\u001b[0;32m    196\u001b[0m \u001b[43m            \u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    197\u001b[0m \u001b[43m            \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[0;32m    198\u001b[0m \u001b[43m            \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    199\u001b[0m \u001b[43m            \u001b[49m\u001b[43mrun_type\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mparser\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[0;32m    200\u001b[0m \u001b[43m        \u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m    201\u001b[0m     \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m    202\u001b[0m         \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_call_with_config(\n\u001b[0;32m    203\u001b[0m             \u001b[38;5;28;01mlambda\u001b[39;00m inner_input: \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mparse_result([Generation(text\u001b[38;5;241m=\u001b[39minner_input)]),\n\u001b[0;32m    204\u001b[0m             \u001b[38;5;28minput\u001b[39m,\n\u001b[0;32m    205\u001b[0m             config,\n\u001b[0;32m    206\u001b[0m             run_type\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mparser\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[0;32m    207\u001b[0m         )\n",
      "File \u001b[1;32mc:\\Users\\rf.yin\\.conda\\envs\\langchain_0_3\\Lib\\site-packages\\langchain_core\\runnables\\base.py:1927\u001b[0m, in \u001b[0;36mRunnable._call_with_config\u001b[1;34m(self, func, input, config, run_type, serialized, **kwargs)\u001b[0m\n\u001b[0;32m   1923\u001b[0m     context \u001b[38;5;241m=\u001b[39m copy_context()\n\u001b[0;32m   1924\u001b[0m     context\u001b[38;5;241m.\u001b[39mrun(_set_config_context, child_config)\n\u001b[0;32m   1925\u001b[0m     output \u001b[38;5;241m=\u001b[39m cast(\n\u001b[0;32m   1926\u001b[0m         Output,\n\u001b[1;32m-> 1927\u001b[0m         \u001b[43mcontext\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m   1928\u001b[0m \u001b[43m            \u001b[49m\u001b[43mcall_func_with_variable_args\u001b[49m\u001b[43m,\u001b[49m\u001b[43m  \u001b[49m\u001b[38;5;66;43;03m# type: ignore[arg-type]\u001b[39;49;00m\n\u001b[0;32m   1929\u001b[0m \u001b[43m            \u001b[49m\u001b[43mfunc\u001b[49m\u001b[43m,\u001b[49m\u001b[43m  \u001b[49m\u001b[38;5;66;43;03m# type: ignore[arg-type]\u001b[39;49;00m\n\u001b[0;32m   1930\u001b[0m \u001b[43m            \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m  \u001b[49m\u001b[38;5;66;43;03m# type: ignore[arg-type]\u001b[39;49;00m\n\u001b[0;32m   1931\u001b[0m \u001b[43m            \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m   1932\u001b[0m \u001b[43m            \u001b[49m\u001b[43mrun_manager\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m   1933\u001b[0m \u001b[43m            \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m   1934\u001b[0m \u001b[43m        \u001b[49m\u001b[43m)\u001b[49m,\n\u001b[0;32m   1935\u001b[0m     )\n\u001b[0;32m   1936\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[0;32m   1937\u001b[0m     run_manager\u001b[38;5;241m.\u001b[39mon_chain_error(e)\n",
      "File \u001b[1;32mc:\\Users\\rf.yin\\.conda\\envs\\langchain_0_3\\Lib\\site-packages\\langchain_core\\runnables\\config.py:396\u001b[0m, in \u001b[0;36mcall_func_with_variable_args\u001b[1;34m(func, input, config, run_manager, **kwargs)\u001b[0m\n\u001b[0;32m    394\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m run_manager \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m accepts_run_manager(func):\n\u001b[0;32m    395\u001b[0m     kwargs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mrun_manager\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m run_manager\n\u001b[1;32m--> 396\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[1;32mc:\\Users\\rf.yin\\.conda\\envs\\langchain_0_3\\Lib\\site-packages\\langchain_core\\output_parsers\\base.py:194\u001b[0m, in \u001b[0;36mBaseOutputParser.invoke.<locals>.<lambda>\u001b[1;34m(inner_input)\u001b[0m\n\u001b[0;32m    186\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21minvoke\u001b[39m(\n\u001b[0;32m    187\u001b[0m     \u001b[38;5;28mself\u001b[39m,\n\u001b[0;32m    188\u001b[0m     \u001b[38;5;28minput\u001b[39m: Union[\u001b[38;5;28mstr\u001b[39m, BaseMessage],\n\u001b[0;32m    189\u001b[0m     config: Optional[RunnableConfig] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[0;32m    190\u001b[0m     \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any,\n\u001b[0;32m    191\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m T:\n\u001b[0;32m    192\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(\u001b[38;5;28minput\u001b[39m, BaseMessage):\n\u001b[0;32m    193\u001b[0m         \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_call_with_config(\n\u001b[1;32m--> 194\u001b[0m             \u001b[38;5;28;01mlambda\u001b[39;00m inner_input: \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mparse_result\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m    195\u001b[0m \u001b[43m                \u001b[49m\u001b[43m[\u001b[49m\u001b[43mChatGeneration\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmessage\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43minner_input\u001b[49m\u001b[43m)\u001b[49m\u001b[43m]\u001b[49m\n\u001b[0;32m    196\u001b[0m \u001b[43m            \u001b[49m\u001b[43m)\u001b[49m,\n\u001b[0;32m    197\u001b[0m             \u001b[38;5;28minput\u001b[39m,\n\u001b[0;32m    198\u001b[0m             config,\n\u001b[0;32m    199\u001b[0m             run_type\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mparser\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[0;32m    200\u001b[0m         )\n\u001b[0;32m    201\u001b[0m     \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m    202\u001b[0m         \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_call_with_config(\n\u001b[0;32m    203\u001b[0m             \u001b[38;5;28;01mlambda\u001b[39;00m inner_input: \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mparse_result([Generation(text\u001b[38;5;241m=\u001b[39minner_input)]),\n\u001b[0;32m    204\u001b[0m             \u001b[38;5;28minput\u001b[39m,\n\u001b[0;32m    205\u001b[0m             config,\n\u001b[0;32m    206\u001b[0m             run_type\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mparser\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[0;32m    207\u001b[0m         )\n",
      "File \u001b[1;32mc:\\Users\\rf.yin\\.conda\\envs\\langchain_0_3\\Lib\\site-packages\\langchain_core\\output_parsers\\openai_tools.py:298\u001b[0m, in \u001b[0;36mPydanticToolsParser.parse_result\u001b[1;34m(self, result, partial)\u001b[0m\n\u001b[0;32m    296\u001b[0m             \u001b[38;5;28;01mcontinue\u001b[39;00m\n\u001b[0;32m    297\u001b[0m         \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m--> 298\u001b[0m             \u001b[38;5;28;01mraise\u001b[39;00m e\n\u001b[0;32m    299\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfirst_tool_only:\n\u001b[0;32m    300\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m pydantic_objects[\u001b[38;5;241m0\u001b[39m] \u001b[38;5;28;01mif\u001b[39;00m pydantic_objects \u001b[38;5;28;01melse\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n",
      "File \u001b[1;32mc:\\Users\\rf.yin\\.conda\\envs\\langchain_0_3\\Lib\\site-packages\\langchain_core\\output_parsers\\openai_tools.py:293\u001b[0m, in \u001b[0;36mPydanticToolsParser.parse_result\u001b[1;34m(self, result, partial)\u001b[0m\n\u001b[0;32m    288\u001b[0m         msg \u001b[38;5;241m=\u001b[39m (\n\u001b[0;32m    289\u001b[0m             \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mTool arguments must be specified as a dict, received: \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m    290\u001b[0m             \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mres[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124margs\u001b[39m\u001b[38;5;124m'\u001b[39m]\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m    291\u001b[0m         )\n\u001b[0;32m    292\u001b[0m         \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(msg)\n\u001b[1;32m--> 293\u001b[0m     pydantic_objects\u001b[38;5;241m.\u001b[39mappend(\u001b[43mname_dict\u001b[49m\u001b[43m[\u001b[49m\u001b[43mres\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mtype\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m]\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mres\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43margs\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m)\n\u001b[0;32m    294\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m (ValidationError, \u001b[38;5;167;01mValueError\u001b[39;00m) \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[0;32m    295\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m partial:\n",
      "File \u001b[1;32mc:\\Users\\rf.yin\\.conda\\envs\\langchain_0_3\\Lib\\site-packages\\pydantic\\main.py:214\u001b[0m, in \u001b[0;36mBaseModel.__init__\u001b[1;34m(self, **data)\u001b[0m\n\u001b[0;32m    212\u001b[0m \u001b[38;5;66;03m# `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks\u001b[39;00m\n\u001b[0;32m    213\u001b[0m __tracebackhide__ \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[1;32m--> 214\u001b[0m validated_self \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m__pydantic_validator__\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mvalidate_python\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdata\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mself_instance\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[0;32m    215\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m validated_self:\n\u001b[0;32m    216\u001b[0m     warnings\u001b[38;5;241m.\u001b[39mwarn(\n\u001b[0;32m    217\u001b[0m         \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mA custom validator is returning a value other than `self`.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m'\u001b[39m\n\u001b[0;32m    218\u001b[0m         \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mReturning anything other than `self` from a top level model validator isn\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mt supported when validating via `__init__`.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m    219\u001b[0m         \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mSee the `model_validator` docs (https://docs.pydantic.dev/latest/concepts/validators/#model-validators) for more details.\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[0;32m    220\u001b[0m         stacklevel\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m2\u001b[39m,\n\u001b[0;32m    221\u001b[0m     )\n",
      "\u001b[1;31mValidationError\u001b[0m: 10 validation errors for NovelDataListModel\nnovel_list.0.type\n  Field required [type=missing, input_value={'emotion': '', 'speaker'...墙点了一支烟。'}, input_type=dict]\n    For further information visit https://errors.pydantic.dev/2.10/v/missing\nnovel_list.0.character\n  Field required [type=missing, input_value={'emotion': '', 'speaker'...墙点了一支烟。'}, input_type=dict]\n    For further information visit https://errors.pydantic.dev/2.10/v/missing\nnovel_list.1.type\n  Field required [type=missing, input_value={'emotion': '', 'speaker'...青春，真可爱！'}, input_type=dict]\n    For further information visit https://errors.pydantic.dev/2.10/v/missing\nnovel_list.1.character\n  Field required [type=missing, input_value={'emotion': '', 'speaker'...青春，真可爱！'}, input_type=dict]\n    For further information visit https://errors.pydantic.dev/2.10/v/missing\nnovel_list.2.type\n  Field required [type=missing, input_value={'emotion': '', 'speaker'...小萝莉走过去。'}, input_type=dict]\n    For further information visit https://errors.pydantic.dev/2.10/v/missing\nnovel_list.2.character\n  Field required [type=missing, input_value={'emotion': '', 'speaker'...小萝莉走过去。'}, input_type=dict]\n    For further information visit https://errors.pydantic.dev/2.10/v/missing\nnovel_list.3.type\n  Field required [type=missing, input_value={'emotion': '', 'speaker'...伸向了小萝莉。'}, input_type=dict]\n    For further information visit https://errors.pydantic.dev/2.10/v/missing\nnovel_list.3.character\n  Field required [type=missing, input_value={'emotion': '', 'speaker'...伸向了小萝莉。'}, input_type=dict]\n    For further information visit https://errors.pydantic.dev/2.10/v/missing\nnovel_list.4.type\n  Field required [type=missing, input_value={'emotion': '', 'speaker'...里骂道：禽兽。'}, input_type=dict]\n    For further information visit https://errors.pydantic.dev/2.10/v/missing\nnovel_list.4.character\n  Field required [type=missing, input_value={'emotion': '', 'speaker'...里骂道：禽兽。'}, input_type=dict]\n    For further information visit https://errors.pydantic.dev/2.10/v/missing"
     ]
    }
   ],
   "source": [
    "from langchain_ollama import ChatOllama\n",
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "from langchain_openai import ChatOpenAI\n",
    "from langchain_core.messages import HumanMessage\n",
    "from typing import Optional, List\n",
    "from pydantic import BaseModel, Field\n",
    "\n",
    "\n",
    "# 使用pydantic来定义一个数据模型\n",
    "class NovelData(BaseModel):\n",
    "    text: str = Field(description=\"需要润色的小说文本\")\n",
    "    type: str = Field(description=\"该段文本的类型， 可能值为： 旁白， 对话\")\n",
    "    character: Optional[str] = Field(description=\"该段文本的说话角色, 请一定要结合上下文推测说话的角色名称。如果是旁白或引申说明，则该字段为空；如果是对话或内心独白，则该字段为说话角色的名称； \")\n",
    "    emotion: Optional[str] = Field(description=\"该段文本的说话角色的情感， 可能的取值为： '快乐', '悲伤', '愤怒', '恐惧', '惊讶', '焦虑', '羞愧', '自豪', '嫉妒', '爱', '失望', '困惑', '希望', '绝望', '同情', '厌恶', '感激', '无聊', '兴奋', '孤独', '内疚', '骄傲', '谦卑', '渴望', '满足', '好奇', '紧张', '宽慰', '疲惫', '振奋'\")\n",
    "\n",
    "class NovelDataListModel(BaseModel):\n",
    "    novel_list: List[NovelData] = Field(description=\"句子列表\")\n",
    "\n",
    "base_url = \"http://192.168.31.240:11434\"\n",
    "model_name = \"qwen2.5:7b\"\n",
    "api_key = \"xxx\"\n",
    "\n",
    "\n",
    "model = ChatOllama(\n",
    "    model = model_name,\n",
    "    temperature = 0,\n",
    "    base_url = base_url,\n",
    "    format=\"json\"\n",
    ")\n",
    "\n",
    "# model = ChatOpenAI(\n",
    "#     temperature=0, \n",
    "#     model_name=model_name, \n",
    "#     api_key=api_key, \n",
    "#     base_url=base_url)\n",
    "\n",
    "structured_llm = model.with_structured_output(NovelDataListModel)\n",
    "# structured_llm = model\n",
    "\n",
    "user_prompt_text = \"\"\"\n",
    "请将以下文本转换成适合有声书的脚本格式。在处理文本时。\n",
    "\n",
    "\n",
    "下面是小说片段：\n",
    "`{novel_text}`\n",
    "\"\"\"\n",
    "\n",
    "prompt_template = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\"system\", \"\"\"\n",
    "你是一个专业的有声书脚本转换助手，你的任务是将给定的小说片段转换成适合录制有声书的脚本。\n",
    "\n",
    "        \"\"\"),\n",
    "        (\"human\", user_prompt_text)\n",
    "    ]\n",
    ")\n",
    "\n",
    "\n",
    "\n",
    "chain = prompt_template | structured_llm\n",
    "\n",
    "novel_text = \"\"\"\n",
    "故事开始的那天，我照例是上着班，打扫完一片狼藉的宠物店，走出店门口，在隔壁便利店买了一包五块钱的软白沙，疲惫的靠着墙点了一支烟。\n",
    "店门口的台阶上，一字排开坐了一行人，有老有少，有男有女。有个白嫩的小萝莉，全身汗津津的，bra在校服下若隐若现。青春，真可爱青春。\n",
    "我叼着烟看着那个小萝莉，她一边打电话，一边眨巴眨巴眼睛看我，然后看向路边。我又抽了两口烟，一部宝马停在路边，小萝莉走过去，青春，真可爱青春。\n",
    "小萝莉开了宝马车的门上车，开车的是一个戴墨镜的秃顶大叔，大叔抱住了小萝莉，黑黝黝的手伸向了小萝莉。\n",
    "我在心里骂，禽兽。\n",
    "\"\"\"\n",
    "\n",
    "\n",
    "response = chain.invoke({\"novel_text\": novel_text})\n",
    "print(type(response))\n",
    "print(response.model_dump_json(indent=4))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "ename": "ResponseError",
     "evalue": "deepseek-r1:14b does not support tools",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mResponseError\u001b[0m                             Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[1], line 150\u001b[0m\n\u001b[0;32m    134\u001b[0m chain \u001b[38;5;241m=\u001b[39m prompt_template \u001b[38;5;241m|\u001b[39m structured_llm\n\u001b[0;32m    136\u001b[0m novel_text \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\"\"\u001b[39m\n\u001b[0;32m    137\u001b[0m \u001b[38;5;124m故事开始的那天，我照例是上着班，打扫完一片狼藉的宠物店，走出店门口，在隔壁便利店买了一包五块钱的软白沙，疲惫的靠着墙点了一支烟。\u001b[39m\n\u001b[0;32m    138\u001b[0m \u001b[38;5;124m店门口的台阶上，一字排开坐了一行人，有老有少，有男有女。有个白嫩的小萝莉，全身汗津津的，bra在校服下若隐若现。青春，真可爱青春。\u001b[39m\n\u001b[1;32m   (...)\u001b[0m\n\u001b[0;32m    146\u001b[0m \u001b[38;5;124m人在屋檐下，不得不低头。\u001b[39m\n\u001b[0;32m    147\u001b[0m \u001b[38;5;124m\"\"\"\u001b[39m\n\u001b[1;32m--> 150\u001b[0m response \u001b[38;5;241m=\u001b[39m \u001b[43mchain\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\u001b[43m{\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mnovel_text\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mnovel_text\u001b[49m\u001b[43m}\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m    151\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;28mtype\u001b[39m(response))\n\u001b[0;32m    152\u001b[0m \u001b[38;5;28mprint\u001b[39m(response\u001b[38;5;241m.\u001b[39mmodel_dump_json(indent\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m4\u001b[39m))\n",
      "File \u001b[1;32mc:\\Users\\rf.yin\\.conda\\envs\\langchain_0_3\\Lib\\site-packages\\langchain_core\\runnables\\base.py:3024\u001b[0m, in \u001b[0;36mRunnableSequence.invoke\u001b[1;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[0;32m   3022\u001b[0m             \u001b[38;5;28minput\u001b[39m \u001b[38;5;241m=\u001b[39m context\u001b[38;5;241m.\u001b[39mrun(step\u001b[38;5;241m.\u001b[39minvoke, \u001b[38;5;28minput\u001b[39m, config, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[0;32m   3023\u001b[0m         \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m-> 3024\u001b[0m             \u001b[38;5;28minput\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[43mcontext\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\u001b[43mstep\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m   3025\u001b[0m \u001b[38;5;66;03m# finish the root run\u001b[39;00m\n\u001b[0;32m   3026\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n",
      "File \u001b[1;32mc:\\Users\\rf.yin\\.conda\\envs\\langchain_0_3\\Lib\\site-packages\\langchain_core\\runnables\\base.py:5354\u001b[0m, in \u001b[0;36mRunnableBindingBase.invoke\u001b[1;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[0;32m   5348\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21minvoke\u001b[39m(\n\u001b[0;32m   5349\u001b[0m     \u001b[38;5;28mself\u001b[39m,\n\u001b[0;32m   5350\u001b[0m     \u001b[38;5;28minput\u001b[39m: Input,\n\u001b[0;32m   5351\u001b[0m     config: Optional[RunnableConfig] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[0;32m   5352\u001b[0m     \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Optional[Any],\n\u001b[0;32m   5353\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Output:\n\u001b[1;32m-> 5354\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mbound\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m   5355\u001b[0m \u001b[43m        \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[0;32m   5356\u001b[0m \u001b[43m        \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_merge_configs\u001b[49m\u001b[43m(\u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m   5357\u001b[0m \u001b[43m        \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43m{\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m}\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m   5358\u001b[0m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[1;32mc:\\Users\\rf.yin\\.conda\\envs\\langchain_0_3\\Lib\\site-packages\\langchain_core\\language_models\\chat_models.py:286\u001b[0m, in \u001b[0;36mBaseChatModel.invoke\u001b[1;34m(self, input, config, stop, **kwargs)\u001b[0m\n\u001b[0;32m    275\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21minvoke\u001b[39m(\n\u001b[0;32m    276\u001b[0m     \u001b[38;5;28mself\u001b[39m,\n\u001b[0;32m    277\u001b[0m     \u001b[38;5;28minput\u001b[39m: LanguageModelInput,\n\u001b[1;32m   (...)\u001b[0m\n\u001b[0;32m    281\u001b[0m     \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any,\n\u001b[0;32m    282\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m BaseMessage:\n\u001b[0;32m    283\u001b[0m     config \u001b[38;5;241m=\u001b[39m ensure_config(config)\n\u001b[0;32m    284\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m cast(\n\u001b[0;32m    285\u001b[0m         ChatGeneration,\n\u001b[1;32m--> 286\u001b[0m         \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mgenerate_prompt\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m    287\u001b[0m \u001b[43m            \u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_convert_input\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    288\u001b[0m \u001b[43m            \u001b[49m\u001b[43mstop\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mstop\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    289\u001b[0m \u001b[43m            \u001b[49m\u001b[43mcallbacks\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mconfig\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mcallbacks\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    290\u001b[0m \u001b[43m            \u001b[49m\u001b[43mtags\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mconfig\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mtags\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    291\u001b[0m \u001b[43m            \u001b[49m\u001b[43mmetadata\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mconfig\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mmetadata\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    292\u001b[0m \u001b[43m            \u001b[49m\u001b[43mrun_name\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mconfig\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mrun_name\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    293\u001b[0m \u001b[43m            \u001b[49m\u001b[43mrun_id\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mconfig\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpop\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mrun_id\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    294\u001b[0m \u001b[43m            \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    295\u001b[0m \u001b[43m        \u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241m.\u001b[39mgenerations[\u001b[38;5;241m0\u001b[39m][\u001b[38;5;241m0\u001b[39m],\n\u001b[0;32m    296\u001b[0m     )\u001b[38;5;241m.\u001b[39mmessage\n",
      "File \u001b[1;32mc:\\Users\\rf.yin\\.conda\\envs\\langchain_0_3\\Lib\\site-packages\\langchain_core\\language_models\\chat_models.py:786\u001b[0m, in \u001b[0;36mBaseChatModel.generate_prompt\u001b[1;34m(self, prompts, stop, callbacks, **kwargs)\u001b[0m\n\u001b[0;32m    778\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mgenerate_prompt\u001b[39m(\n\u001b[0;32m    779\u001b[0m     \u001b[38;5;28mself\u001b[39m,\n\u001b[0;32m    780\u001b[0m     prompts: \u001b[38;5;28mlist\u001b[39m[PromptValue],\n\u001b[1;32m   (...)\u001b[0m\n\u001b[0;32m    783\u001b[0m     \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any,\n\u001b[0;32m    784\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m LLMResult:\n\u001b[0;32m    785\u001b[0m     prompt_messages \u001b[38;5;241m=\u001b[39m [p\u001b[38;5;241m.\u001b[39mto_messages() \u001b[38;5;28;01mfor\u001b[39;00m p \u001b[38;5;129;01min\u001b[39;00m prompts]\n\u001b[1;32m--> 786\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mgenerate\u001b[49m\u001b[43m(\u001b[49m\u001b[43mprompt_messages\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstop\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mstop\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcallbacks\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcallbacks\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[1;32mc:\\Users\\rf.yin\\.conda\\envs\\langchain_0_3\\Lib\\site-packages\\langchain_core\\language_models\\chat_models.py:643\u001b[0m, in \u001b[0;36mBaseChatModel.generate\u001b[1;34m(self, messages, stop, callbacks, tags, metadata, run_name, run_id, **kwargs)\u001b[0m\n\u001b[0;32m    641\u001b[0m         \u001b[38;5;28;01mif\u001b[39;00m run_managers:\n\u001b[0;32m    642\u001b[0m             run_managers[i]\u001b[38;5;241m.\u001b[39mon_llm_error(e, response\u001b[38;5;241m=\u001b[39mLLMResult(generations\u001b[38;5;241m=\u001b[39m[]))\n\u001b[1;32m--> 643\u001b[0m         \u001b[38;5;28;01mraise\u001b[39;00m e\n\u001b[0;32m    644\u001b[0m flattened_outputs \u001b[38;5;241m=\u001b[39m [\n\u001b[0;32m    645\u001b[0m     LLMResult(generations\u001b[38;5;241m=\u001b[39m[res\u001b[38;5;241m.\u001b[39mgenerations], llm_output\u001b[38;5;241m=\u001b[39mres\u001b[38;5;241m.\u001b[39mllm_output)  \u001b[38;5;66;03m# type: ignore[list-item]\u001b[39;00m\n\u001b[0;32m    646\u001b[0m     \u001b[38;5;28;01mfor\u001b[39;00m res \u001b[38;5;129;01min\u001b[39;00m results\n\u001b[0;32m    647\u001b[0m ]\n\u001b[0;32m    648\u001b[0m llm_output \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_combine_llm_outputs([res\u001b[38;5;241m.\u001b[39mllm_output \u001b[38;5;28;01mfor\u001b[39;00m res \u001b[38;5;129;01min\u001b[39;00m results])\n",
      "File \u001b[1;32mc:\\Users\\rf.yin\\.conda\\envs\\langchain_0_3\\Lib\\site-packages\\langchain_core\\language_models\\chat_models.py:633\u001b[0m, in \u001b[0;36mBaseChatModel.generate\u001b[1;34m(self, messages, stop, callbacks, tags, metadata, run_name, run_id, **kwargs)\u001b[0m\n\u001b[0;32m    630\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i, m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28menumerate\u001b[39m(messages):\n\u001b[0;32m    631\u001b[0m     \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m    632\u001b[0m         results\u001b[38;5;241m.\u001b[39mappend(\n\u001b[1;32m--> 633\u001b[0m             \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_generate_with_cache\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m    634\u001b[0m \u001b[43m                \u001b[49m\u001b[43mm\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    635\u001b[0m \u001b[43m                \u001b[49m\u001b[43mstop\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mstop\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    636\u001b[0m \u001b[43m                \u001b[49m\u001b[43mrun_manager\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrun_managers\u001b[49m\u001b[43m[\u001b[49m\u001b[43mi\u001b[49m\u001b[43m]\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mif\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mrun_managers\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01melse\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[0;32m    637\u001b[0m \u001b[43m                \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    638\u001b[0m \u001b[43m            \u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m    639\u001b[0m         )\n\u001b[0;32m    640\u001b[0m     \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[0;32m    641\u001b[0m         \u001b[38;5;28;01mif\u001b[39;00m run_managers:\n",
      "File \u001b[1;32mc:\\Users\\rf.yin\\.conda\\envs\\langchain_0_3\\Lib\\site-packages\\langchain_core\\language_models\\chat_models.py:851\u001b[0m, in \u001b[0;36mBaseChatModel._generate_with_cache\u001b[1;34m(self, messages, stop, run_manager, **kwargs)\u001b[0m\n\u001b[0;32m    849\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m    850\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m inspect\u001b[38;5;241m.\u001b[39msignature(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_generate)\u001b[38;5;241m.\u001b[39mparameters\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mrun_manager\u001b[39m\u001b[38;5;124m\"\u001b[39m):\n\u001b[1;32m--> 851\u001b[0m         result \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_generate\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m    852\u001b[0m \u001b[43m            \u001b[49m\u001b[43mmessages\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstop\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mstop\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mrun_manager\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrun_manager\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\n\u001b[0;32m    853\u001b[0m \u001b[43m        \u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m    854\u001b[0m     \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m    855\u001b[0m         result \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_generate(messages, stop\u001b[38;5;241m=\u001b[39mstop, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n",
      "File \u001b[1;32mc:\\Users\\rf.yin\\.conda\\envs\\langchain_0_3\\Lib\\site-packages\\langchain_ollama\\chat_models.py:701\u001b[0m, in \u001b[0;36mChatOllama._generate\u001b[1;34m(self, messages, stop, run_manager, **kwargs)\u001b[0m\n\u001b[0;32m    694\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_generate\u001b[39m(\n\u001b[0;32m    695\u001b[0m     \u001b[38;5;28mself\u001b[39m,\n\u001b[0;32m    696\u001b[0m     messages: List[BaseMessage],\n\u001b[1;32m   (...)\u001b[0m\n\u001b[0;32m    699\u001b[0m     \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any,\n\u001b[0;32m    700\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m ChatResult:\n\u001b[1;32m--> 701\u001b[0m     final_chunk \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_chat_stream_with_aggregation\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m    702\u001b[0m \u001b[43m        \u001b[49m\u001b[43mmessages\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstop\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mrun_manager\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mverbose\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mverbose\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\n\u001b[0;32m    703\u001b[0m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m    704\u001b[0m     generation_info \u001b[38;5;241m=\u001b[39m final_chunk\u001b[38;5;241m.\u001b[39mgeneration_info\n\u001b[0;32m    705\u001b[0m     chat_generation \u001b[38;5;241m=\u001b[39m ChatGeneration(\n\u001b[0;32m    706\u001b[0m         message\u001b[38;5;241m=\u001b[39mAIMessage(\n\u001b[0;32m    707\u001b[0m             content\u001b[38;5;241m=\u001b[39mfinal_chunk\u001b[38;5;241m.\u001b[39mtext,\n\u001b[1;32m   (...)\u001b[0m\n\u001b[0;32m    711\u001b[0m         generation_info\u001b[38;5;241m=\u001b[39mgeneration_info,\n\u001b[0;32m    712\u001b[0m     )\n",
      "File \u001b[1;32mc:\\Users\\rf.yin\\.conda\\envs\\langchain_0_3\\Lib\\site-packages\\langchain_ollama\\chat_models.py:602\u001b[0m, in \u001b[0;36mChatOllama._chat_stream_with_aggregation\u001b[1;34m(self, messages, stop, run_manager, verbose, **kwargs)\u001b[0m\n\u001b[0;32m    593\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_chat_stream_with_aggregation\u001b[39m(\n\u001b[0;32m    594\u001b[0m     \u001b[38;5;28mself\u001b[39m,\n\u001b[0;32m    595\u001b[0m     messages: List[BaseMessage],\n\u001b[1;32m   (...)\u001b[0m\n\u001b[0;32m    599\u001b[0m     \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any,\n\u001b[0;32m    600\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m ChatGenerationChunk:\n\u001b[0;32m    601\u001b[0m     final_chunk \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m--> 602\u001b[0m \u001b[43m    \u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mstream_resp\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_create_chat_stream\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmessages\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstop\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\u001b[43m:\u001b[49m\n\u001b[0;32m    603\u001b[0m \u001b[43m        \u001b[49m\u001b[38;5;28;43;01mif\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;129;43;01mnot\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43misinstance\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mstream_resp\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mstr\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m:\u001b[49m\n\u001b[0;32m    604\u001b[0m \u001b[43m            \u001b[49m\u001b[43mchunk\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m \u001b[49m\u001b[43mChatGenerationChunk\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m    605\u001b[0m \u001b[43m                \u001b[49m\u001b[43mmessage\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mAIMessageChunk\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m    606\u001b[0m \u001b[43m                    \u001b[49m\u001b[43mcontent\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m(\u001b[49m\n\u001b[1;32m   (...)\u001b[0m\n\u001b[0;32m    619\u001b[0m \u001b[43m                \u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    620\u001b[0m \u001b[43m            \u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[1;32mc:\\Users\\rf.yin\\.conda\\envs\\langchain_0_3\\Lib\\site-packages\\langchain_ollama\\chat_models.py:589\u001b[0m, in \u001b[0;36mChatOllama._create_chat_stream\u001b[1;34m(self, messages, stop, **kwargs)\u001b[0m\n\u001b[0;32m    586\u001b[0m chat_params \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_chat_params(messages, stop, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[0;32m    588\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m chat_params[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mstream\u001b[39m\u001b[38;5;124m\"\u001b[39m]:\n\u001b[1;32m--> 589\u001b[0m     \u001b[38;5;28;01myield from\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_client\u001b[38;5;241m.\u001b[39mchat(\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mchat_params)\n\u001b[0;32m    590\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m    591\u001b[0m     \u001b[38;5;28;01myield\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_client\u001b[38;5;241m.\u001b[39mchat(\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mchat_params)\n",
      "File \u001b[1;32mc:\\Users\\rf.yin\\.conda\\envs\\langchain_0_3\\Lib\\site-packages\\ollama\\_client.py:167\u001b[0m, in \u001b[0;36mClient._request.<locals>.inner\u001b[1;34m()\u001b[0m\n\u001b[0;32m    165\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m httpx\u001b[38;5;241m.\u001b[39mHTTPStatusError \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[0;32m    166\u001b[0m   e\u001b[38;5;241m.\u001b[39mresponse\u001b[38;5;241m.\u001b[39mread()\n\u001b[1;32m--> 167\u001b[0m   \u001b[38;5;28;01mraise\u001b[39;00m ResponseError(e\u001b[38;5;241m.\u001b[39mresponse\u001b[38;5;241m.\u001b[39mtext, e\u001b[38;5;241m.\u001b[39mresponse\u001b[38;5;241m.\u001b[39mstatus_code) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[0;32m    169\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m line \u001b[38;5;129;01min\u001b[39;00m r\u001b[38;5;241m.\u001b[39miter_lines():\n\u001b[0;32m    170\u001b[0m   part \u001b[38;5;241m=\u001b[39m json\u001b[38;5;241m.\u001b[39mloads(line)\n",
      "\u001b[1;31mResponseError\u001b[0m: deepseek-r1:14b does not support tools"
     ]
    }
   ],
   "source": [
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "from langchain_openai import ChatOpenAI\n",
    "from langchain_core.messages import HumanMessage\n",
    "from typing import Optional, List\n",
    "from pydantic import BaseModel, Field\n",
    "from langchain_ollama import ChatOllama\n",
    "\n",
    "\n",
    "# 使用pydantic来定义一个数据模型\n",
    "class NovelData(BaseModel):\n",
    "    text: str = Field(description=\"需要润色的小说文本\")\n",
    "    type: str = Field(description=\"该段文本的类型， 可能值为： 旁白， 对话\")\n",
    "    character: Optional[str] = Field(description=\"该段文本的说话角色, 请一定要结合上下文推测说话的角色名称。如果是旁白或引申说明，则该字段为空；如果是对话或内心独白，则该字段为说话角色的名称； \")\n",
    "    emotion: Optional[str] = Field(description=\"该段文本的说话角色的情感， 可能的取值为： '快乐', '悲伤', '愤怒', '恐惧', '惊讶', '焦虑', '羞愧', '自豪', '嫉妒', '爱', '失望', '困惑', '希望', '绝望', '同情', '厌恶', '感激', '无聊', '兴奋', '孤独', '内疚', '骄傲', '谦卑', '渴望', '满足', '好奇', '紧张', '宽慰', '疲惫', '振奋'\")\n",
    "\n",
    "class NovelDataListModel(BaseModel):\n",
    "    novel_list: List[NovelData] = Field(description=\"句子列表\")\n",
    "\n",
    "base_url = \"http://192.168.31.240:11434\"\n",
    "model_name = \"deepseek-r1:14b\"\n",
    "\n",
    "\n",
    "model = ChatOllama(\n",
    "    model = model_name,\n",
    "    temperature = 0,\n",
    "    base_url = base_url,\n",
    "    format=\"json\",\n",
    "    num_ctx= 131072\n",
    "\n",
    ")\n",
    "structured_llm = model.with_structured_output(NovelDataListModel)\n",
    "\n",
    "# structured_llm = model.with_structured_output(NovelDataListModel)\n",
    "\n",
    "user_prompt_text = \"\"\"\n",
    "请将以下文本转换成适合有声书的脚本格式。在处理文本时,参考以下示例：\n",
    "\n",
    "## 示例1\n",
    "原文: “张帆，干嘛呢？是不是又偷懒？”一个粗里粗气的声音将我从沉思中惊醒。\n",
    "输出: \n",
    "[\n",
    "    {{\n",
    "        \"text\": \"张帆，干嘛呢？是不是又偷懒？\",\n",
    "        \"type\": \"对话\",\n",
    "        \"character\": \"荷花\",\n",
    "        \"emotion\": \"愤怒\"\n",
    "    }},\n",
    "    {{\n",
    "        \"text\": \"一个粗里粗气的声音将我从沉思中惊醒。\",\n",
    "        \"type\": \"旁白\",\n",
    "        \"character\": null,\n",
    "        \"emotion\": \"厌恶\"\n",
    "    }}\n",
    "]\n",
    "\n",
    "\n",
    "## 示例2\n",
    "原文: “这不可能！”李明大声喊道，他的脸因为愤怒而涨得通红。“你一定在骗我。”\n",
    "输出: \n",
    "[\n",
    "    {{\n",
    "        \"text\": \"这不可能！\",\n",
    "        \"type\": \"对话\",\n",
    "        \"character\": \"李明\",\n",
    "        \"emotion\": \"愤怒\"\n",
    "    }},\n",
    "    {{\n",
    "        \"text\": \"李明大声喊道，他的脸因为愤怒而涨得通红。\",\n",
    "        \"type\": \"旁白\",\n",
    "        \"character\": null,\n",
    "        \"emotion\": \"厌恶\"\n",
    "    }},\n",
    "    {{\n",
    "        \"text\": \"你一定在骗我。\",\n",
    "        \"type\": \"对话\",\n",
    "        \"character\": \"李明\",\n",
    "        \"emotion\": \"愤怒\"\n",
    "    }}\n",
    "]\n",
    "\n",
    "\n",
    "\n",
    "## 示例3\n",
    "原文: 我把烟头丢掉，奴颜媚骨的问：“花姐有什么吩咐。”\n",
    "输出: \n",
    "[\n",
    "    {{\n",
    "        \"text\": \"我把烟头丢掉，奴颜媚骨的问\",\n",
    "        \"type\": \"旁白\",\n",
    "        \"character\": \"我\",\n",
    "        \"emotion\": \"谦卑\"\n",
    "    }},\n",
    "    {{\n",
    "        \"text\": \"花姐有什么吩咐。\",\n",
    "        \"type\": \"对话\",\n",
    "        \"character\": \"我\",\n",
    "        \"emotion\": \"内疚\"\n",
    "    }}\n",
    "]\n",
    "\n",
    "下面是小说片段：\n",
    "`{novel_text}`\n",
    "\"\"\"\n",
    "\n",
    "prompt_template = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\"system\", \"\"\"\n",
    "你是一个专业的有声书脚本转换助手，你的任务是将给定的小说片段转换成适合录制有声书的脚本。请按照以下规则进行转换：\n",
    "\n",
    "1. **区分对话和旁白**：\n",
    "   - 识别并分离文本中的人物对话（通常位于双引号内）和旁白（描述性文字）。对话部分应被特别标注出来，以便于后续的声音演绎。\n",
    "   \n",
    "2. **角色对话处理**：\n",
    "   - 对于每一句人物对话，请指明说话者的身份（如果已知），并建议适当的情绪、语气或音调变化来表达该句话的情感背景。例如，“愤怒地说”、“轻柔地问”等。\n",
    "   - 如果原文中没有明确指出是谁在说话，请根据上下文合理推测，并在脚本中标注出可能的说话者。\n",
    "\n",
    "3. **旁白处理**：\n",
    "   - 将旁白部分用叙述的方式呈现，确保语言流畅且易于理解。旁白应当用来建立场景、描述动作或解释事件，帮助听众更好地想象故事的发展。\n",
    "   - 注意旁白中的情感色彩，如紧张、轻松、悲伤等，并通过语速、语调的变化传达给听众。\n",
    "\n",
    "4. **特殊说明**：\n",
    "   - 如果文本中有任何特殊的格式化要求（如强调某些词语、使用特定的停顿等），请在脚本中明确指出。\n",
    "   - 对于不常见的词汇或者专有名词，考虑添加发音指导以确保正确朗读。\n",
    "\n",
    "请严格按照上述指导原则执行转换任务，确保最终生成的有声书脚本能准确反映原文的情感和氛围，同时为听众提供愉悦的听觉体验。\n",
    "\n",
    "        \"\"\"),\n",
    "        (\"human\", user_prompt_text)\n",
    "    ]\n",
    ")\n",
    "\n",
    "\n",
    "\n",
    "chain = prompt_template | structured_llm\n",
    "\n",
    "novel_text = \"\"\"\n",
    "故事开始的那天，我照例是上着班，打扫完一片狼藉的宠物店，走出店门口，在隔壁便利店买了一包五块钱的软白沙，疲惫的靠着墙点了一支烟。\n",
    "店门口的台阶上，一字排开坐了一行人，有老有少，有男有女。有个白嫩的小萝莉，全身汗津津的，bra在校服下若隐若现。青春，真可爱青春。\n",
    "我叼着烟看着那个小萝莉，她一边打电话，一边眨巴眨巴眼睛看我，然后看向路边。我又抽了两口烟，一部宝马停在路边，小萝莉走过去，青春，真可爱青春。\n",
    "小萝莉开了宝马车的门上车，开车的是一个戴墨镜的秃顶大叔，大叔抱住了小萝莉，黑黝黝的手伸向了小萝莉。\n",
    "我在心里骂，禽兽。\n",
    "苦逼啊，我悟了，这个纸醉金迷的花花都市，并不是一个农村孩子的天堂。\n",
    "“张帆，干嘛呢？是不是又偷懒？”一个粗里粗气的声音将我从沉思中惊醒。\n",
    "一扭头，店长何花，老板是她干爹，我们叫她花姐，正怒目冷对着我。\n",
    "我把烟头丢掉，奴颜媚骨的问：“花姐有什么吩咐。”\n",
    "人在屋檐下，不得不低头。\n",
    "\"\"\"\n",
    "\n",
    "\n",
    "response = chain.invoke({\"novel_text\": novel_text})\n",
    "print(type(response))\n",
    "print(response.model_dump_json(indent=4))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "pydantic-ai",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
